package math;

import static math.ExpressionBuilder.or;
import static math.ExpressionBuilder.and;

public class And implements BooleanExpression {

  private BooleanExpression arg1;
  
  private BooleanExpression arg2;

  private And(BooleanExpression arg1, BooleanExpression arg2) {
    this.arg1 = arg1;
    this.arg2 = arg2;
  }

  public BooleanExpression getArg1() {
    return arg1;
  }
  
  public BooleanExpression getArg2() {
    return arg2;
  }
  
  @Override
  public int countMembers() {
    return 1 + arg1.countMembers() + arg2.countMembers();
  }

  @Override
  public Expression simplify() {
    return this;
  }

  @Override
  public String toString() {
    return '(' + arg1.toString() + '&' + arg2.toString() + ")";
  }

  @Override
  public boolean equals(Object obj) {
    if (obj instanceof And) {
      And and2 = (And) obj;
      return and2.arg1.equals(arg1) && and2.arg2.equals(arg2);
    } else
      return false;
  }
  
  @Override
  public boolean matches(Expression expr) {
    if (expr instanceof And) {
      And eAnd = (And) expr;
      return arg1.matches(eAnd.getArg1()) && arg2.matches(eAnd.getArg2());
    } else
      return false;
  }

  @Override
  public int hashCode() {
    return arg1.hashCode() ^ (arg2.hashCode() * 156994);
  }

  @Override
  public <R> R accept(ExpressionVisitor<R> visitor) {
    return visitor.visitAnd(this);
  }

  public static BooleanExpression createAnd(BooleanExpression arg1, BooleanExpression arg2) {
    return new And(arg1, arg2);
  }

  @Override
  public BooleanExpression toDNF() {
    BooleanExpression newArg1 = arg1.toDNF();
    BooleanExpression newArg2 = arg2.toDNF();
    if (newArg1 instanceof Or){
      Or or = (Or) newArg1;
      return or(and(or.getArg1(), newArg2), and(or.getArg2(), newArg2)).toDNF();
    }
    if (newArg2 instanceof Or){
      Or or = (Or) newArg2;
      return or(and(newArg1, or.getArg1()), and(newArg1, or.getArg2())).toDNF();
    }
    if (newArg1 == arg1 && newArg2 == arg2)
      return this;
    else
      return and(newArg1, newArg2);
    
  }
}